Skip to content

Conversation

@nonactress
Copy link

@nonactress nonactress commented Jan 15, 2026

안녕하세요 승현님!!! 로또 미션 이후로 리뷰어님으로 오랜만에 뵙는 것 같은데 벌써 마지막 미션이라는게 정말 시간이 빠른 것 같습니다 ^^ 잘 부탁드립니다!!!

미션 요구사항 및 해결방법

  1. JWT 관련 로직을 roomescape와 같은 계층의 auth 패키지의 클래스로 분리하고 불필요한 DB 접근을 최소화 하세요.
  • auth 패키지를 만들어서 JwtTokenProvider 를 위치 시켰습니다! 또한 빈 등록을 위해 jwtConfig 를 이용하여 빈으로 등록하였습니다!
  1. schema.sql 대신 데이터베이스를 초기화 해주기 위해 실행하는 클래스를 만드세요. 스프링이 실행될 때 동작해야 합니다.token 생성에 필요한 비밀키값을 외부 파일로 분리하세요.
  • CommandLineRunner 을 이용하여 dataLoader를 만들어 보았습니다!
  • DataLoader 에서는 사용자 정보만 초기화
  • TestDataLoader 에서는 테스트에 필요한 사전 값 초기화 -> @ActiveProfile 을 이용해서 테스트 코드시 사용해보았습니다!
  • application-secret 을 통해 키 값과 만료 시간을 분리해보았습니다!
  1. ec2나 서버에서 배포를 할 수 있게 배포 스크립트를 작성하세요.
  • deploy.sh
    1. 저장소에서 최신 코드를 pull 받음
    1. 프로젝트 빌드
    1. 기존에 실행 중인 애플리케이션의 PID를 찾아 종료
    1. 빌드된 애플리케이션 실행
  • 순서대로 적어보았습니다!

1) 모든 도메인 엔티티로 변경
2) TimeRepository 퀴리문 변경
3) DataInitializer로 초기값 설정
@nonactress nonactress changed the title [그리디] 서현진 Spring 배포 7, 8, 9 단계 미션 제출합니다. [그리디] 서현진 Spring Core 배포 7, 8, 9 단계 미션 제출합니다. Jan 15, 2026
Copy link

@supernovaMK supernovaMK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 현진님~ 반갑습니다. 이번 리뷰어를 맡게 된 김민기입니다.

미션 요구사항 모두 잘 구현해주셨네요~
코멘트 몇 개 남겼는데 확인해주세요! 추가적으로 이야기 나누고 싶으신 것 있으시다면 편하게 남겨주세요!

Comment on lines +1 to +2
security.jwt.token.secret-key=thisismysecretkeyandgreedyzzangandsoftwarefighting
security.jwt.token.expire-length=3600000

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public repo를 사용하는 상황에서 secret key를 어떻게 공유하고 관리할 수 있을까요?

Copy link
Author

@nonactress nonactress Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

찾아 보니 크게 2가지 방법이 있는 것 같습니다!!


1. 환경 변수 사용

코드에는 변수명만 적고, 실제 값은 서버 시스템 환경 변수로 등록하는 것입니다.

예시 (파일 : application.yml)
api: key: ${API_KEY_VALUE}

2. 실행 시 인자 전달

애플리케이션을 실행할 때 직접 값을 주입합니다.

java -jar app.jar --api.key=your-secret-key-123

Jws<Claims> claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
return !claims.getBody().getExpiration().before(new Date());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

토큰이 만료가 되었는지 따로 검사하시는 이유가 있나요?

parseClaimsJws과정에서 만료 검사를 하는 것으로 알고 있어서요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseClaimsJws 가 토큰의 만료 시간을 검사 해주는 기능도 있는 지 몰랐습니다!! 이와 관련해서 만약 토큰이 만료 기한이 지났다면 ExpiredJwtException 를 던지는 것을 찾아보았습니다! 이를 반영하여 만료시간 예외 처리하도록 반영해보겠습니다!

반영 커밋 : c5bdf60

throw new AuthenticationException("인증되지 않은 사용자입니다.");
}

return memberService.findByToken(token);
Copy link

@supernovaMK supernovaMK Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MemberService 를 참조하는 이유가 무엇인가요?

현진님이 정의하신 AuthService의 책임이 궁금해요!
AuthService에서 repository에 접근하여 member객체를 찾아왔을 수 도 있었어서요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AuthService의 책임


AuthService는 요청에서 토큰을 추출하고 그 토큰이 유효한지 검증하는 인증 프로세스라고 생각합니다!
반면, 특정 토큰을 가진 회원을 찾는 구체적인 로직(조회 방식, 예외 처리 등)은 Member 도메인을 관리하는 MemberService의 책임이라고 생각했습니다!!

AuthService에서 repository에 접근하여 member객체를 찾아왔을 수 도 있었어서요!


말씀하신 대로 AuthService 에서 직접 레포지토리에 접근할 수도 있지만, 그렇게 되면 Member 엔티티를 다루는 로직이 여러 서비스로 흩어지게 되어 나중에 Member 조회 로직이 변경될 때 유지 보수가 어려울 것 같아서 서비스를 사용해 보았습니다!

import org.springframework.context.annotation.Configuration;

@Configuration
public class JwtConfig {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Config 방식을 사용해보니 어떤 점이 좋았나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 만든 클래스를 빈으로 등록시켜 간편하게 매번 사용할 때 마다 생성하지 않아도 되서 편했던 것 같습니다!

import roomescape.time.TimeRepository;

@Component
public class ProductionDataLoader implements CommandLineRunner {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.sql 파일을 활용하는 대신 CommandLineRunner를 활용했을 때 어떤 차이가 있었나요?

장단점은 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sql


장점 - 퀴리 문으로 작동해서 매우 빠르다
단점 - 퀴리 문법을 알아야 한다....

CommandLineRunner


장점 - 자바 로직으로 데이터를 만들 수 있다, 복잡한 엔티티 연관관계 보다 쉽게 만들 수 있다!
단점 - 속도가 느리다....

차이는 속도적인 차이가 존재하고 sql 엔티티 연관관계 구조를 매번 적용 시켜줘야 한다는 단점이 있는 거 같습니다!

@@ -0,0 +1,42 @@
#!/bin/bash

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현진님이 작성해주신 배포스크립트를 활용하면 어떻게 배포할 수 있나요?

즉, 이 배포 스크립트 실행 전에 해야할 사전 작업이 있나요?

Comment on lines +11 to +12
@SQLDelete(sql = "UPDATE theme SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 두 어노테이션은 왜 사용하나요?😃

public MemberService(MemberDao memberDao) {
this.memberDao = memberDao;
public MemberService(MemberRepository memberRepository, JwtTokenProvider jwtTokenProvider) {
this.memberRepository = memberRepository;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dao를 사용하시다 jpa를 사용해주셨군요! 어떤 차이점이 있으셨나요?

각각의 장단점을 느끼셨나요? 저도 궁금해요!


List<Reservation> findByDateAndThemeId(String date, Long themeId);

@Query("SELECT r FROM Reservation r JOIN FETCH r.time JOIN FETCH r.theme WHERE r.member.id = :memberId")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JOIN FETCH를 써주신 이유가 궁금해요!


import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFINED_PORT를 사용하면 어떤 문제가 생길 수 있을까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants